package me.zhengjie.modules.system.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;

import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.system.domain.Dept;
import me.zhengjie.modules.system.domain.Region;
import me.zhengjie.modules.system.domain.vo.RegionQueryCriteria;
import me.zhengjie.modules.system.mapper.RegionMapper;
import me.zhengjie.modules.system.service.RegionService;
import me.zhengjie.utils.FileUtil;
import lombok.RequiredArgsConstructor;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import me.zhengjie.utils.PageUtil;

import java.util.*;
import java.io.IOException;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

import me.zhengjie.utils.PageResult;

/**
* @description 服务实现
* @author 程康
* @date 2024-12-12
**/
@Service
@RequiredArgsConstructor
public class RegionServiceImpl extends ServiceImpl<RegionMapper, Region> implements RegionService {

    private final RegionMapper RegionMapper;

    @Override
    public PageResult<Region> queryAll(RegionQueryCriteria criteria, Page<Object> page){
        IPage<Region> regions = RegionMapper.findAll(criteria, page);
        List<Region> records = regions.getRecords();
        if(!records.isEmpty()) {
            for (Region region : records) {
                List<Region> child = this.queryAllRegion(Long.valueOf(region.getId()), false);
                region.setSubCount(child.size());
                region.setChildren(child);
                region.setHasChildren(region.getSubCount() > 0);
            }
        }
        return PageUtil.toPage(regions);
    }

    @Override
    public List<Region> queryAll(RegionQueryCriteria criteria){
        return RegionMapper.findAll(criteria);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(Region resources) {
        // 1. 校验层级关系
        validateLevelAndParent(resources);
        // 2. 校验唯一性
        validateUnique(resources);
        // 3. 校验状态
        validateStatus(resources);
        // 4. 校验排序值
        validateSort(resources);
        
        save(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Region resources) {
        // 1. 获取原数据
        Region oldRegion = getById(resources.getId());
        if (oldRegion == null) {
            throw new BadRequestException("待更新的地区不存在");
        }
        
        // 2. 校验层级关系
        validateLevelAndParent(resources);
        // 3. 校验唯一性(排除自身)
        validateUnique(resources);
        // 4. 校验状态
        validateStatus(resources);
        // 5. 校验排序值
        validateSort(resources);
        
        oldRegion.copy(resources);
        saveOrUpdate(oldRegion);
    }

    /**
     * 校验层级关系
     */
    private void validateLevelAndParent(Region region) {
        // 校验层级深度
        if (region.getLevel() > 3) {
            throw new BadRequestException("地区层级不能超过3级");
        }

        // 校验父子关系
        if (region.getLevel() == 1 && region.getParentId() != 0) {
            throw new BadRequestException("一级地区的父ID必须为0");
        }
        
        if (region.getLevel() > 1) {
            if (region.getParentId() == 0) {
                throw new BadRequestException("非一级地区必须有父级地区");
            }
            
            // 检查父级地区是否存在
            Region parent = getById(region.getParentId());
            if (parent == null) {
                throw new BadRequestException("父级地区不存在");
            }
            
            // 检查父级地区的level是否合理
            if (parent.getLevel() >= region.getLevel()) {
                throw new BadRequestException("子级地区的层级必须大于父级地区");
            }
        }
    }

    /**
     * 校验唯一性
     */
    private void validateUnique(Region region) {
        // 检查同级下是否有重名
        LambdaQueryWrapper<Region> nameWrapper = new LambdaQueryWrapper<>();
        nameWrapper.eq(Region::getParentId, region.getParentId())
                  .eq(Region::getName, region.getName());
        if (region.getId() != null) {
            nameWrapper.ne(Region::getId, region.getId());
        }
        if (count(nameWrapper) > 0) {
            throw new BadRequestException("同一父级下已存在相同名称的地区");
        }

        // 检查编码是否重复
        LambdaQueryWrapper<Region> codeWrapper = new LambdaQueryWrapper<>();
        codeWrapper.eq(Region::getCode, region.getCode());
        if (region.getId() != null) {
            codeWrapper.ne(Region::getId, region.getId());
        }
        if (count(codeWrapper) > 0) {
            throw new BadRequestException("地区编码已存在");
        }
    }

    /**
     * 校验状态
     */
    private void validateStatus(Region region) {
        if (region.getParentId() != 0 && Boolean.TRUE.equals(region.getStatus())) {
            Region parent = getById(region.getParentId());
            if (parent != null && !parent.getStatus()) {
                throw new BadRequestException("父级地区被禁用时，子级地区不能启用");
            }
        }
    }

    /**
     * 校验排序值
     */
    private void validateSort(Region region) {
        if (region.getRegionSort() != null) {
            LambdaQueryWrapper<Region> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Region::getParentId, region.getParentId())
                   .eq(Region::getRegionSort, region.getRegionSort());
            if (region.getId() != null) {
                wrapper.ne(Region::getId, region.getId());
            }
            if (count(wrapper) > 0) {
                throw new BadRequestException("同级地区下已存在相同的排序值");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(List<Integer> ids) {
        // 检查是否有子地区
        for (Integer id : ids) {
            LambdaQueryWrapper<Region> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Region::getParentId, id);
            if (count(wrapper) > 0) {
                throw new BadRequestException("存在子地区，不能直接删除");
            }
        }
        removeBatchByIds(ids);
    }

    @Override
    public void download(List<Region> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (Region region : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            // 处理父级ID - 如果是0则显示为"顶级地区"
            map.put("父级地区ID", region.getParentId() == 0 ? "顶级地区" : region.getParentId().toString());
            map.put("地区名称", region.getName());
            // 处理地区级别 - 将数字转换为对应的描述文字
            String levelDesc;
            switch (region.getLevel()) {
                case 1:
                    levelDesc = "大区";
                    break;
                case 2:
                    levelDesc = "省市";
                    break;
                case 3:
                    levelDesc = "县区";
                    break;
                default:
                    levelDesc = "未知级别";
            }
            map.put("地区级别", levelDesc);
            map.put("地区编码", region.getCode());
            // 处理状态 - 将布尔值转换为启用/禁用
            map.put("状态", region.getStatus() ? "启用" : "禁用");
            map.put("创建时间", region.getCreatedAt());
            map.put("更新时间", region.getUpdatedAt());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public List<Region> queryAllRegion(Long parentId, Boolean sort) {
        LambdaQueryWrapper<Region> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        if (sort) {
            lambdaQueryWrapper.orderByDesc(Region::getRegionSort);
        }

        if (Objects.nonNull(parentId)) {
            lambdaQueryWrapper.eq(Region::getParentId, parentId);
        }
        List<Region> records = this.list(lambdaQueryWrapper);
        if(!records.isEmpty()) {
            for (Region region : records) {
                region.setSubCount(this.queryAllRegion(Long.valueOf(region.getId()),false).size());
            }
        }
        return records;
    }

    @Override
    public Object getDeptSuperior(List<Long> ids, Boolean exclude) {
        Set<Region> regionSet = new LinkedHashSet<>();
        for (Long parentId : ids) { // 接收的 ids 即为 parentId
            List<Region> regions = getSuperior(parentId, new ArrayList<>(), new HashSet<>());
            if (exclude) {
                // 编辑时不显示自身及子级，避免环形问题
                for (Region data : regions) {
                    if (data.getId().equals(parentId)) {
                        data.setSubCount(data.getSubCount() - 1);
                    }
                }
                regions = regions.stream().filter(i -> !ids.contains(i.getId())).collect(Collectors.toList());
            }
            regionSet.addAll(regions);
        }
        return buildTree(new ArrayList<>(regionSet));
    }


    private List<Region> getSuperior(Long parentId, List<Region> regions, Set<Long> visited) {
        // 防止循环调用
        if (parentId == null || visited.contains(parentId)) {
            return regions;
        }

        // 标记当前节点为已访问
        visited.add(parentId);

        // 使用 queryAllRegion 获取当前层级的所有 Region
        List<Region> regionList = this.queryAllRegion(parentId, false);

        if (!regionList.isEmpty()) {
            for (Region region : regionList) {
                regions.add(region); // 添加当前节点
                // 递归获取上级节点
                getSuperior(Long.valueOf(region.getId()), regions, visited);
            }
        }

        return regions;
    }




    public Object buildTree(List<Region> regionList) {
        // 用于存储最终的树形结构
        List<Region> trees = new ArrayList<>();
        // 用于存储非顶级节点的集合
        List<Region> regions = new ArrayList<>();
        // 获取所有地区的名称列表
        List<String> regionNames = regionList.stream().map(Region::getName).collect(Collectors.toList());

        boolean isChild;
        for (Region region : regionList) {
            isChild = false;
            // 如果 parentId 为 null，则为顶级节点，加入树集合
            if (region.getParentId() == null) {
                trees.add(region);
            }
            // 遍历所有节点，查找当前节点的子节点
            for (Region it : regionList) {
                if (it.getParentId() != null && region.getId().equals(it.getParentId())) {
                    isChild = true;
                    // 更新父节点的子节点计数
                    if (region.getSubCount() == null) {
                        region.setSubCount(0);
                    }
                    region.setSubCount(region.getSubCount() + 1);
                    // 添加子节点到父节点的 children 列表
                    if (region.getChildren() == null) {
                        region.setChildren(new ArrayList<>());
                    }
                    region.getChildren().add(it);
                }
            }
            // 如果是子节点，则加入 regions 集合
            if (isChild) {
                regions.add(region);
            } else if (region != null && region.getParentId() != null) {
                // 如果父节点不存在，则也加入 regions 集合
                regions.add(region);
            }
        }

        // 如果树集合为空，则将 regions 集合作为树
        if (CollectionUtil.isEmpty(trees)) {
            trees = regions;
        }

        // 构建返回结果
        Map<String, Object> map = new HashMap<>(2);
        map.put("totalElements", regions.size());
        map.put("content", CollectionUtil.isEmpty(trees) ? regions : trees);
        return map;
    }

}